using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Drawing;
using System.Threading;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using ViewOnCore.Helper.Collection;
using ViewOnCore.Helper.WPF;
using ViewOnCore.HostContract.Media;
using ViewOnCore.Device;
using ViewOnCore.HostContract;

namespace UI.Control
{

    static public class AlbumCoverManager
    {

        #region Variables

        static public ExtObservableCollection<AlbumCoverItem> Items = new ExtObservableCollection<AlbumCoverItem>();

        static private Dictionary<string, Bitmap> _imagesCache = new Dictionary<string, Bitmap>();

        static private Thread _thread;

        static private Dispatcher _dispatcher;
        static private BackgroundWorker _worker = new BackgroundWorker();
        static private DispatcherPriority _priority = DispatcherPriority.DataBind;

        #endregion

        #region Constructor

        static AlbumCoverManager()
        {
            System.Windows.Application.Current.Exit += new ExitEventHandler(Current_Exit);

            //Items.LazyRefresh = true;

            _worker.WorkerSupportsCancellation = true;

            _worker.DoWork += new DoWorkEventHandler(worker_DoWork);
        }

        #endregion

        #region Properties

        static public Dispatcher Dispatcher
        {
            set
            {
                _dispatcher = value;
            }
        }

        #endregion

        #region Application_Exit

        static void Current_Exit(object sender, ExitEventArgs e)
        {
            _worker.CancelAsync();
        }

        #endregion

        #region Load

        static public void Reload()
        {
            DoUpdate(false);
        }

        #endregion

        #region Update

        static public void Update()
        {
            DoUpdate(true);
        }

        #endregion

        #region DoUpdate

        static public void DoUpdate(bool isUpdate)
        {
            // Here we have 2 Threads, why ?
            //------------------------------
            // The "DoUpdate" is called from the "Dispatcher thread", but using a thread
            // here we avoid to block the "Dispatcher thread"
            //
            // The second thread from the BackgroundWorker is used to do the
            // background processing.

            Thread thread = new Thread(new ParameterizedThreadStart(DoUpdateAsync));
            thread.Start(isUpdate);
        }

        static private void DoUpdateAsync(object state)
        {
            _worker.CancelAsync();

            while (_worker.IsBusy)
                Thread.Sleep(250);

            _worker.RunWorkerAsync(state);
        }

        static void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            //---- Is update or complete reload
            bool isUpdate = (bool)e.Argument;

            ExtObservableCollection<MediaData> medias = Host.MediaService.CurrentMediaDeviceFeature.MediaDatas;

            if (Host.MediaService.CurrentMediaDeviceFeatureItem != null)
                medias = Host.MediaService.CurrentMediaDeviceFeatureItem.MediaDatas;

            //---- Cancel
            if (_worker.CancellationPending)
            {
                e.Cancel = true;
                return;
            }

            if (!isUpdate)
            {
                _dispatcher.Invoke(_priority,
                    (DelegateInvoker)delegate
                    {
                        Items.Clear();
                    });
                _imagesCache.Clear();
            }

            if (_imagesCache.Count < 1)
            {
                //---- All
                _dispatcher.Invoke(_priority,
                    (DelegateInvoker)delegate
                    {
                        if (CheckCancelation(e))
                            return;
                        Items.Add(new AlbumCoverItem(null, null, null, "ALL"));
                    });
                _imagesCache.Add("_", null);
            }

            try
            {
                for (int index = 0; index < medias.Count; index++)
                {
                    if (_worker.CancellationPending)
                    {
                        e.Cancel = true;
                        return;
                    }

                    Music music = medias[index] as Music;

                    string key = CreateKey(music);

                    if (_imagesCache.ContainsKey(key))
                    {
                        // Update the image
                        if (music.Image != null)
                            _imagesCache[key] = music.Image;
                        continue;
                    }

                    if (music.Image != null)
                    {
                        _imagesCache.Add(key, music.Image);
                        _dispatcher.Invoke(_priority,
                                (DelegateInvoker)delegate
                                {
                                    if (CheckCancelation(e))
                                        return;
                                    Items.Add(new AlbumCoverItem(key, music.Image, music));
                                });
                    }
                    else
                    {
                        _imagesCache.Add(key, null);
                        _dispatcher.Invoke(_priority,
                                (DelegateInvoker)delegate
                                {
                                    if (CheckCancelation(e))
                                        return;
                                    Items.Add(new AlbumCoverItem(key, (Bitmap)null, music));
                                });
                    }
                }
            }
            finally
            {
                _dispatcher.Invoke(_priority,
                                (DelegateInvoker)delegate
                                {
                                    if (CheckCancelation(e))
                                        return;
                                    Items.ForceRefresh();
                                });
            }

            //---- Update all the images
            if (isUpdate)
                foreach (AlbumCoverItem item in Items)
                    if (item.Key != null)
                        item.Refresh(_imagesCache[item.Key]);
        }

        #endregion

        #region CheckCancelation

        static private bool CheckCancelation(DoWorkEventArgs e)
        {
            if (_worker.CancellationPending)
            {
                e.Cancel = true;
                return true;
            }

            return false;
        }

        #endregion

        #region CreateKey

        static private string CreateKey(Music music)
        {
            return music.Album;
        }

        #endregion

    }

    #region AlbumCoverItem

    sealed public class AlbumCoverItem : ViewOnCore.Helper.BusinessObject.AbstractBusinessObject
    {
        static private BitmapImage DefaultBitmapSource = null;
        static private BitmapImage AllBitmapSource = null;

        private Bitmap _bitmap;
        private string _text;
        public object Tag;
        public string Key;

        public AlbumCoverItem(string key, Bitmap bitmap, object tag)
            : this(key, bitmap, tag, null)
        {
        }

        public AlbumCoverItem(string key, Bitmap bitmap, object tag, string text)
        {
            _bitmap = bitmap;
            _text = text;
            Tag = tag;
            Key = key;
        }

        public void Refresh(Bitmap bitmap)
        {
            _bitmap = bitmap;
            OnPropertyChanged("BitmapSource");
        }

        public BitmapSource BitmapSource
        {
            get
            {
                if (Tag == null)
                {
                    if (AllBitmapSource == null)
                        AllBitmapSource = new BitmapImage(new Uri(@"pack://application:,,,/_images/PartMusic/All.png"));
                    return AllBitmapSource;
                }

                if (_bitmap == null)
                {
                    if (DefaultBitmapSource == null)
                        DefaultBitmapSource = new BitmapImage(new Uri(@"pack://application:,,,/_images/logo/logo150x150.png"));
                    return DefaultBitmapSource;
                }

                return System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(_bitmap.GetHbitmap(),
                                                        IntPtr.Zero,
                                                        Int32Rect.Empty,
                                                        System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
            }
        }

        public string Text
        {
            get
            {
                return _text;
            }
            set
            {
                _text = value;
            }
        }

        public string Title01
        {
            get
            {
                if (Tag is Music)
                    return ((Music)Tag).Artist;
                return "";
            }
        }

        public string Title02
        {
            get
            {
                if (Tag is Music)
                    return ((Music)Tag).Album;
                return "";
            }
        }

        public override bool Equals(object obj)
        {
            AlbumCoverItem item = obj as AlbumCoverItem;
            return item.Key == this.Key;
        }

    }

    #endregion

}
